React - Componenten
Bijna alles in React bestaat uit componenten, en die kunnen klassecomponenten of eenvoudige componenten zijn. De meeste React-apps hebben veel kleine componenten en alles wordt in de hoofdcomponent van de app geladen. Componenten staan meestal een eigen bestand.
React gaat uit van de vaststelling dat de logica om informatie weer te geven (rendering) inherent gekoppeld aan andere UI-logica: hoe gebeurtenissen worden afgehandeld, hoe de status verandert in de tijd en hoe de gegevens worden voorbereid voor weergave.
In plaats van op kunstmatige wijze technologieën te scheiden door markup en logica in afzonderlijke bestanden op te slaan, maakt React een onderscheid tussen concerns (bedoelingen) door elke bedoeling in afzonderlijke, los gekoppelde, componenten onder te brengen.
We leren twee soorten componenten maken en we leggen de nadruk op encapsulatie en herbruikbaarheid ervan:
Een component met props maken
De gebruikersinterface wordt opgesplitst in onafhankelijke, herbruikbare componenten die elk op zich één bepaalde verantwoordelijkheid hebben. Deze pagina geeft een inleiding op het idee van componenten. Hier maken we kennis met de fundamentele React concepten. Voor meer gedetailleerde informatie verwijzen we naar de component-API-referentie.
Conceptueel zijn componenten JavaScript-functies. Ze accepteren willekeurige invoer ("props" genoemd) en geven React-elementen terug die beschrijven wat er op het scherm moet verschijnen.
- Functie-componenten
- Het schrijven van een functie is de gemakkelijkste manier om een component te definiëren. We nemen het Marvel voorbeeld uit React - Knooppunten en breken de code op in componenten. We maken een functie-component die de taak op zich neemt om 1 Marvelpersonnage op een tegel te tonen:
function MarvelCharacter(props) { return (<div style={marvelCharacterStyle.tile}> {props.name} <img src={props.imageUrl} style={marvelCharacterStyle.image} alt={"foto van " + props.name} /> </div>); }
- We gebruiken de kennis die we hebben over objecten in JavaScript om de CSS stijlregels te groeperen in 1 stijlknoopunt:
const marvelCharacterStyle = { list: { color: 'green', display: 'flex', flexWrap: 'wrap' }, tile: { color: 'white', backgroundColor: 'red', textAlign: 'center', width: '10em', fontSize: '2em', fontFamily: 'Arial', paddingTop: '0.5em' }, image: { color: 'blue', width: '10em', paddingTop: '0.5em' } };
-
We passen ons
marvel
knooppunt aan en gebruiken JSX om met een zelfgemaakte tag met de naamMarvelCharacter
de functie-component te laten uitvoeren. We geven twee attributen mee, die door JSX zullen worden omgezet naar een JS object en als argument aan de functie-component worden doorgegeven:const marvel = ( <div> <h1>Marvel Personnages</h1> <div style={marvelCharacterStyle}> <MarvelCharacter name="Avengers" imageUrl="http://i.annihil.us/u/prod/marvel/i/mg/0/03/523219b086a17.jpg" /> </div> </div> );
- Nu moeten we nog de andere personnages toevoegen. We zouden nog 4 MarvelCharacter tags manueel kunnen toevoegen. Maar we gaan opnieuw onze kennis van JavaScript arrays en objecten gebruiken.
- Voor elke personnage maken we een object met de nodige kenmerken en die stoppen we in een array:
// object met de gegevens van de Marvelpersonnages const MarvelCharacters = [ { name: 'Avengers', imageUrl: 'http://i.annihil.us/u/prod/marvel/i/mg/0/03/523219b086a17.jpg' }, { name: 'Hulk', imageUrl: 'http://i.annihil.us/u/prod/marvel/i/mg/5/a0/538615ca33ab0.jpg' }, { name: 'Spider-Man', imageUrl: 'http://i.annihil.us/u/prod/marvel/i/mg/3/50/526548a343e4b.jpg' }, { name: 'Spider-Girl', imageUrl: 'http://i.annihil.us/u/prod/marvel/i/mg/1/70/4c003adccbe4f.jpg' }, { name: 'X-Man', imageUrl: 'http://i.annihil.us/u/prod/marvel/i/mg/d/10/535febd73f84f.jpg' } ]
- om dan met de
map
methode voor elk element in de array een tegel te genereren:const marvel = ( <div> <h1>Marvel Personnages</h1> <div style={marvelCharacterStyle.list}> {MarvelCharacters.map(element => MarvelCharacter(element))} </div> </div> );
-
De functie-component
MarvelCharacter
en het stijl-objectmarvelCharacterStyle
blijven ongewijzigd. Hier volgt de volledige code tot nu toe van static-react/component.html:<!DOCTYPE html> <html lang="nl"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Snel starten met React</title> <!-- Note: when deploying, replace "development.js" with "production.min.js". --> <script src="https://unpkg.com/react@16/umd/react.development.js" crossorigin></script> <script src="https://unpkg.com/react-dom@16/umd/react-dom.development.js" crossorigin></script> <script src="https://unpkg.com/@babel/standalone/babel.min.js"></script> <script type="text/babel"> // object met de gegevens van de Marvelpersonnages const MarvelCharacters = [ { name: 'Avengers', imageUrl: 'http://i.annihil.us/u/prod/marvel/i/mg/0/03/523219b086a17.jpg' }, { name: 'Hulk', imageUrl: 'http://i.annihil.us/u/prod/marvel/i/mg/5/a0/538615ca33ab0.jpg' }, { name: 'Spider-Man', imageUrl: 'http://i.annihil.us/u/prod/marvel/i/mg/3/50/526548a343e4b.jpg' }, { name: 'Spider-Girl', imageUrl: 'http://i.annihil.us/u/prod/marvel/i/mg/1/70/4c003adccbe4f.jpg' }, { name: 'X-Man', imageUrl: 'http://i.annihil.us/u/prod/marvel/i/mg/d/10/535febd73f84f.jpg' } ] // we gaan veel keer createElement moeten gebruiken // we maken een afkorting const e = React.createElement; const marvelCharacterStyle = { list: { color: 'green', display: 'flex', flexWrap: 'wrap' }, tile: { color: 'white', backgroundColor: 'red', textAlign: 'center', width: '10em', fontSize: '2em', fontFamily: 'Arial', paddingTop: '0.5em' }, image: { color: 'blue', width: '10em', paddingTop: '0.5em' } }; function MarvelCharacter(props) { return (<div style={marvelCharacterStyle.tile}> {props.name} <img src={props.imageUrl} style={marvelCharacterStyle.image} alt={"foto van " + props.name} /> </div>); } const marvel = ( <div> <h1>Marvel Personnages</h1> <div style={marvelCharacterStyle.list}> {MarvelCharacters.map(element => MarvelCharacter(element))} </div> </div> ); </script> </head> <body> <div id="root"></div> <script type="text/babel"> ReactDOM.render(marvel, document.querySelector('#root')) </script> </body> </html>
- Voor elke personnage maken we een object met de nodige kenmerken en die stoppen we in een array:
- Het schrijven van een functie is de gemakkelijkste manier om een component te definiëren. We nemen het Marvel voorbeeld uit React - Knooppunten en breken de code op in componenten. We maken een functie-component die de taak op zich neemt om 1 Marvelpersonnage op een tegel te tonen:
- Klassencomponenten
- We gaan nog een stap verder en willen alle functionaliteit van de Marvelpersonnages in 1 component onderbrengen (encapsuation) die we gemakkelijk op om het even welke webpagina kunnen plaatsen. Daarmee willen we het nut van componenten illustreren:
- 1 verantwoordelijkheid
- herbruikbaar
- Stappen:
- Maak een ES6-klasse met dezelfde naam die
React.Component
uitbreidt. - Voeg er een enkele lege methode aan toe, genaamd
render()
. - Plaats de code die de reactknooppunten toont in de body van de
render()
methode. - We verwijzen naar de eigenschappen en methoden van de klasse met het
this
keyword. Vervang bijvoorbeeldprops
doorthis.props
in derender()
body. -
Om de waarschuwing te vermijden dat er een
key
moet worden verstrekt voor lijstitems voegen we die als attribuut toe. Een 'key' is een unieke waarde die je moet opgeven bij het maken van lijsten met elementen. We voegen dus eenkey
attribuut toe aan de div die één Marvelpersonnage bevat.. - De
Marvel
klassencomponent stoppen we in een apart bestand met de naam js/marvel.js:class Marvel extends React.Component { // we gaan veel keer createElement moeten gebruiken // we maken een afkorting e = React.createElement; marvelCharacterStyle = { list: { color: 'green', display: 'flex', flexWrap: 'wrap' }, tile: { color: 'white', backgroundColor: 'red', textAlign: 'center', width: '10em', fontSize: '2em', fontFamily: 'Arial', paddingTop: '0.5em' }, image: { color: 'blue', width: '10em', paddingTop: '0.5em' } }; MarvelCharacter(props) { return (<div style={this.marvelCharacterStyle.tile} key={props.name}> {props.name} <img src={props.imageUrl} style={this.marvelCharacterStyle.image} alt={"foto van " + props.name} /> </div>); } render() { return ( <div> <h1>{this.props.heading}</h1> <div style={this.marvelCharacterStyle.list}> {this.props.list.map(element => this.MarvelCharacter(element))} </div> </div> ); } }
- Nu we de component netjes afgeschermd in een bestand hebben staan kunnen die heel eenvoudig op een webpagina gebruiken. De moeite om de component wordt ruimschoots vergoed door het gemak waarmee we de component op een webpagina kunnen zetten. Het voorbeeld staat in static-react/class-component.html;
<meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Snel starten met React</title> <!-- Note: when deploying, replace "development.js" wi="textth "production.min.js". --> <script src="https://unpkg.com/react@16/umd/react.development.js" crossorigin></script> <script src="https://unpkg.com/react-dom@16/umd/react-dom.development.js" crossorigin></script> <script src="https://unpkg.com/@babel/standalone/babel.min.js"></script> <script type="text/babel" src="js/marvel.js"></script> <script type="text/babel"> // object met de gegevens van de Marvelpersonnages const MarvelCharacters = [ { name: 'Avengers', imageUrl: 'http://i.annihil.us/u/prod/marvel/i/mg/0/03/523219b086a17.jpg' }, { name: 'Hulk', imageUrl: 'http://i.annihil.us/u/prod/marvel/i/mg/5/a0/538615ca33ab0.jpg' }, { name: 'Spider-Man', imageUrl: 'http://i.annihil.us/u/prod/marvel/i/mg/3/50/526548a343e4b.jpg' }, { name: 'Spider-Girl', imageUrl: 'http://i.annihil.us/u/prod/marvel/i/mg/1/70/4c003adccbe4f.jpg' }, { name: 'X-Man', imageUrl: 'http://i.annihil.us/u/prod/marvel/i/mg/d/10/535febd73f84f.jpg' } ] </script> </head> <body> <div id="root"></div> <script type="text/babel"> ReactDOM.render(<Marvel list = {MarvelCharacters} heading = "John's keuze"/>, document.querySelector('#root')) </script> </body> </html>
- We laden het js bestand waarin de
Marvel
component staat mettype="text/babel"
. - De data staat in een
object
met de naamMarvelCharacters
en is extern aan de component. Dat is nodig omdat deMarvel
component ook andere Marvel-personnages moet kunnen tonen. - De titel geven we door als de waarde van het
heading
attribuut van het Marvel element en de data geven we mee als de waarde van hetlist
attribuut. Achter de schermen worden die twee attributen en hun waarden in hetprops
object van de Marvel component omgezet en doorgegeven. - Aan de
render
methode van hetReactDOM
object geven we hetMarvel
element door om op de pagina weergegeven te worden. Achter de schermen gaat JSX dat eigengemaakt<Marvel/>
XML element vervangen door de klasseMarvel
.
- We laden het js bestand waarin de
- We hebben net gezien dat zo'n op zichzelf bestaande component gemakkelijk te gebruiken is. Nu gaan tonen dat die ook gemakkelijk te hergebruiken is. We gaan de selectie van Farah tonen.
- We maken een object met de personnages die Farah gekozen heeft:
const FarahChoiceMarvelCharacters = [ { name: 'Agent Brand', imageUrl: 'http://i.annihil.us/u/prod/marvel/i/mg/4/60/52695285d6e7e.jpg' }, { name: 'Anita Blake', imageUrl: 'http://i.annihil.us/u/prod/marvel/i/mg/2/a0/4c0038fa14452.jpg' }, { name: 'Butterfly', imageUrl: 'http://i.annihil.us/u/prod/marvel/i/mg/8/00/4c0030b5dbc50.jpg' }, { name: 'Spider-Girl', imageUrl: 'http://i.annihil.us/u/prod/marvel/i/mg/1/70/4c003adccbe4f.jpg' }, { name: 'Lyja', imageUrl: 'http://i.annihil.us/u/prod/marvel/i/mg/3/40/4c003594c52e8.jpg' } ]
- We wijzigen de html in de body van static-react/class-component.html. We voegen in de #root div twee div's toe om respectievelijk de keuze van John en Farah te tonen. We roepen twee keer de render methode op ReactDom om de keuzes te renderen:
<body> <div id="root"> <div id="john"></div> <div id="farah"></div> </div> <script type="text/babel"> ReactDOM.render(<Marvel list={MarvelCharacters} heading="John's keuze" />, document.querySelector('#john')) ReactDOM.render(<Marvel list={FarahChoiceMarvelCharacters} heading="Farah's keuze" />, document.querySelector('#farah')) </script> </body>
- Met dit als resultaat:
- We maken een object met de personnages die Farah gekozen heeft:
- Maak een ES6-klasse met dezelfde naam die
- We gaan nog een stap verder en willen alle functionaliteit van de Marvelpersonnages in 1 component onderbrengen (encapsuation) die we gemakkelijk op om het even welke webpagina kunnen plaatsen. Daarmee willen we het nut van componenten illustreren: